
package com.shop.cloud.pay.admin.controller.wx;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReceiverRequest;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingRequest;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingUnfreezeRequest;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.ProfitSharingService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.security.annotation.Inside;
import com.shop.cloud.pay.admin.config.WxPayConfiguration;
import com.shop.cloud.pay.admin.service.PayConfigService;
import com.shop.cloud.pay.common.constant.PayConstants;
import com.shop.cloud.pay.common.entity.PayConfig;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * 微信支付
 *
 * @author
 * @date 2019-03-23 21:26:35
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/wxpay")
@Tag(description = "wxpay", name = "微信支付")
public class WxPayController {

	private final PayConfigService payConfigService;

	/**
	 * 调用统一下单接口，并组装生成支付所需参数对象.
	 *
	 * @param request 统一下单请求参数
	 * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
	 */
	@Operation(summary = "调用统一下单接口")
	@Inside
	@PostMapping("/unifiedOrder")
	public R unifiedOrder(@RequestBody WxPayUnifiedOrderRequest request) {
		PayConfig payConfig = payConfigService.findByType(PayConstants.PAY_TYPE_1);
		WxPayConfig wxPayConfig = new WxPayConfig();
		wxPayConfig.setSubMchId(request.getSubMchId());
		WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
		try {
			if("NATIVE".equals(request.getTradeType())){//trade_type=NATIVE时
				request.setProductId(request.getOutTradeNo());
			}
			if(PayConstants.PAY_MODEL_2.equals(payConfig.getModel())){//普通模式
				if("JSAPI".equals(request.getTradeType())){//trade_type=JSAPI时（小程序、公众号h5）
					request.setAppid(request.getSubAppId());
					request.setOpenid(request.getSubOpenid());
				}
				request.setSubMchId(null);
				request.setSubAppId(null);
				request.setSubOpenid(null);
				wxPayConfig.setSubMchId(null);
				wxPayConfig.setSubAppId(null);
			}else{
				if("APP".equals(request.getTradeType())){//trade_type=APP时
					request.setSubAppId(request.getAppid());
				}
				//服务商模式并已开户了分账，资金冻结开启分账
				if(CommonConstants.YES.equals(payConfig.getDividedEnable())){
					request.setProfitSharing("Y");
				}
			}
			return R.ok(wxPayService.createOrder(request));
		} catch (WxPayException e) {
			return R.failed(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
		}
	}

	/**
	 * 处理支付回调
	 * @param xmlData
	 * @return
	 */
	@Operation(summary = "处理支付回调")
	@Inside
	@PostMapping("/notifyOrder")
	public R notifyOrder(@RequestBody String xmlData) {
		WxPayOrderNotifyResult rs = WxPayOrderNotifyResult.fromXML(xmlData);
//		String appId = rs.getAppid();
		String SubMchId = rs.getSubMchId();
		WxPayConfig wxPayConfig = new WxPayConfig();
//		wxPayConfig.setAppId(appId);
		wxPayConfig.setSubMchId(SubMchId);
		try {
			WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
			WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
			return R.ok(notifyResult);
		} catch (WxPayException e) {
			log.error(e.getMessage());
			return R.failed(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
		} catch (Exception e) {
			log.error(e.getMessage());
			return R.failed(e.getMessage());
		}
	}

	/**
	 * <pre>
	 * 微信支付-申请退款.
	 * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
	 * 接口链接：https://api.mch.weixin.qq.com/secapi/pay/refund
	 * </pre>
	 *
	 * @param request 请求对象
	 * @return 退款操作结果 wx pay refund result
	 * @throws WxPayException the wx pay exception
	 */
	@Operation(summary = "申请退款")
	@Inside
	@PostMapping("/refundOrder")
	public R refundOrder(@RequestBody WxPayRefundRequest request) {
		WxPayConfig wxPayConfig = new WxPayConfig();
		wxPayConfig.setAppId(request.getAppid());
		wxPayConfig.setSubMchId(request.getSubMchId());
		PayConfig payConfig = payConfigService.findByType(PayConstants.PAY_TYPE_1);
		if(PayConstants.PAY_MODEL_2.equals(payConfig.getModel())){//普通模式
			request.setSubMchId(null);
			request.setSubAppId(null);
			wxPayConfig.setSubMchId(null);
			wxPayConfig.setSubAppId(null);
		}
		WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
		try {
			return R.ok(wxPayService.refund(request));
		} catch (WxPayException e) {
			e.printStackTrace();
			return R.failed(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
		}
	}

	/**
	 * 处理退款回调
	 * @param xmlData
	 * @return
	 */
	@Operation(summary = "处理退款回调")
	@Inside
	@PostMapping("/notifyRefunds")
	public R notifyRefunds(@RequestBody String xmlData) {
		WxPayOrderNotifyResult rs = WxPayOrderNotifyResult.fromXML(xmlData);
		String appId = rs.getAppid();
		String SubMchId = rs.getSubMchId();
		WxPayConfig wxPayConfig = new WxPayConfig();
		wxPayConfig.setAppId(appId);
		wxPayConfig.setSubMchId(SubMchId);
		WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
		try {
			WxPayRefundNotifyResult notifyResult = wxPayService.parseRefundNotifyResult(xmlData);
			return R.ok(notifyResult);
		} catch (WxPayException e) {
			e.printStackTrace();
			return R.failed(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
		}
	}

	/**
	 * 查询订单
	 * @param request
	 * @return
	 */
	@Operation(summary = "查询订单")
	@Inside
	@PostMapping("/queryOrder")
	public R queryOrder(@RequestBody WxPayOrderQueryRequest request) {
		WxPayConfig wxPayConfig = new WxPayConfig();
		wxPayConfig.setAppId(request.getAppid());
		wxPayConfig.setSubMchId(request.getSubMchId());
		PayConfig payConfig = payConfigService.findByType(PayConstants.PAY_TYPE_1);
		if(PayConstants.PAY_MODEL_2.equals(payConfig.getModel())){//普通模式
			request.setSubMchId(null);
			request.setSubAppId(null);
			wxPayConfig.setSubMchId(null);
			wxPayConfig.setSubAppId(null);
		}
		WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
		try {
			WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(request);
			return R.ok(wxPayOrderQueryResult);
		} catch (WxPayException e) {
			return R.failed(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
		}
	}

	/**
	 * 分账接口
	 *
	 * @param request 统一下单请求参数
	 * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
	 */
	@Operation(summary = "分账接口")
	@Inside
	@PostMapping("/profitsharing")
	public R profitSharing(@RequestBody ProfitSharingRequest request) {
		WxPayConfig wxPayConfig = new WxPayConfig();
		wxPayConfig.setAppId(request.getAppid());
		wxPayConfig.setSubMchId(request.getSubMchId());
		WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
		ProfitSharingService profitSharingService = wxPayService.getProfitSharingService();
		try {
			profitSharingService.profitSharing(request);
			return R.ok();
		} catch (WxPayException e) {
			//报关系未绑定错误，则调绑定方法
			if("RECEIVER_INVALID".equals(e.getErrCode()) || StrUtil.contains(e.getErrCodeDes(), "分账接收方关系不存在")){
				//获取分账时的接收方信息
				JSONArray receivers = JSONUtil.parseArray(request.getReceivers());
				ProfitSharingReceiverRequest profitSharingReceiverRequest = new ProfitSharingReceiverRequest();
				for(int i = 0; i<receivers.size(); i++){
					try {
						//分账关系绑定
						JSONObject receiverJS= (JSONObject) receivers.get(i);
						receiverJS.set("relation_type", "SERVICE_PROVIDER");
						String receiver = JSONUtil.toJsonStr(receiverJS);
						profitSharingReceiverRequest.setReceiver(receiver);
						profitSharingService.addReceiver(profitSharingReceiverRequest);
					} catch (WxPayException e2) {
						e2.printStackTrace();
						return R.failed(e2.getErrCodeDes()+e2.getCustomErrorMsg());
					}
				}
				try {
					//关系绑定成功，则重新调用分账方法
					profitSharingService.profitSharing(request);
					return R.ok();
				} catch (WxPayException e3) {
					e3.printStackTrace();
					return R.failed(e3.getErrCodeDes()+e3.getCustomErrorMsg());
				}
			}else{
				e.printStackTrace();
				return R.failed(e.getErrCodeDes()+e.getCustomErrorMsg());
			}
		}
	}

	/**
	 * <pre>
	 * 1、不需要进行分账的订单，可直接调用本接口将订单的金额全部解冻给特约商户
	 * 2、调用多次分账接口后，需要解冻剩余资金时，调用本接口将剩余的分账金额全部解冻给特约商户
	 * 3、已调用请求单次分账后，剩余待分账金额为零，不需要再调用此接口。
	 * 接口频率：30QPS
	 * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=25_5&index=6
	 * 接口链接：https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish
	 * </pre>
	 *
	 * @param request .
	 * @return .
	 * @throws WxPayException the wx pay exception
	 */
	@Operation(summary = "完结分账")
	@Inside
	@PostMapping("/profitsharingfinish")
	public R profitSharingFinish(@RequestBody ProfitSharingUnfreezeRequest request) {
		WxPayConfig wxPayConfig = new WxPayConfig();
		wxPayConfig.setAppId(request.getAppid());
		wxPayConfig.setSubMchId(request.getSubMchId());
		WxPayService wxPayService = WxPayConfiguration.getPayService(wxPayConfig);
		ProfitSharingService profitSharingService = wxPayService.getProfitSharingService();
		try {
			profitSharingService.profitSharingFinish(request);
			return R.ok();
		} catch (WxPayException e) {
			return R.failed(e.getReturnMsg() + "" + e.getCustomErrorMsg() + "" + e.getErrCodeDes());
		}
	}

}
